package com.qf;

import com.alibaba.fastjson.JSONObject;
import com.qf.entity.*;
import com.qf.service.HappyBeanHistoryService;
import com.qf.service.IUserService;
import com.qf.utils.RegretAndReopenUntils;
import com.qf.utils.RoomManagerUtils;
import com.qf.utils.SessionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 创建一个WebSocket的对外开放的端点服务
 */
@Component
@ServerEndpoint("/gobank")
public class WebSocketConfig {

    //房间编号
    private static AtomicInteger number = new AtomicInteger(0);

    private static HappyBeanHistoryService happyBeanHistoryService;

    private static IUserService userService;

    @Autowired
    public void setHappyBeanHistoryService(HappyBeanHistoryService happyBeanHistoryService) {
        WebSocketConfig.happyBeanHistoryService = happyBeanHistoryService;
    }

    @Autowired
    public void setUserService(IUserService userService) {
        WebSocketConfig.userService = userService;
    }

    /**
     * 当有一个客户端连接了服务器 就会触发该方法
     */
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("有一个客户端连接了服务器！");
    }

    /**
     * 当有一个客户端连接断开后，会触发该方法
     *
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        System.out.println("有一个客户端断开了连接！");
        //删除当前连接管理的房间
        RoomManagerUtils.removeRoom(session);
    }

    /**
     * 当有一个客户端发生异常时，会触发该方法
     */
    @OnError
    public void onError(Session session, Throwable t) {
        System.out.println("有一个客户端发生了异常！");
        t.printStackTrace();
    }

    /**
     * 接收到一个客户端的消息
     */
    @OnMessage
    public void onMessage(String msg, Session session) {
        System.out.println("接收到客户端的消息：" + msg);

        //解析json
        JSONObject jsonObject = JSONObject.parseObject(msg);
        //获取当前的消息类型
        int msgType = jsonObject.getIntValue("msgType");
        /*
           客户端 -> 服务器：
           200 - 创建房间
           201 - 加入房间
           202 - 落子信息
           203 - 聊天消息
           204 - 语音消息
           205 - 悔棋请求
           206 - 悔棋确认
           207 - 重开请求
           208 - 重开确认

           服务器 -> 客户端：
           300 - 房间未找到
           301 - 房间已经满人
           302 - 房间密码错误

           400 - 有人加入房间，游戏已经开始
           401 - 加入房间成功，游戏已经开始
           402 - 对手的落子信息
           403 - 自己落子成功
           404 - 对方的聊天消息
           405 - 发送给对方的音频消息
           406 - 发送悔棋信息
           407 - 发送确认悔棋信息
           408 - 发送重开信息
           409 - 发送重开确认信息
         */
        if (msgType == 200) {
            //创建房间
            createRoom(jsonObject, session);
        } else if (msgType == 201) {
            //有人加入房间
            addRoom(jsonObject, session);
        } else if (msgType == 202) {
            //有人落子 落子信息
            drawGo(jsonObject, session);
        } else if (msgType == 203) {
            //聊天消息
            infoHandler(jsonObject, session);
        } else if (msgType == 204) {
            //语音消息
            audioHandler(jsonObject, session);
        } else if (msgType == 205) {
            //悔棋请求
            regretMessage(jsonObject, session);
        } else if (msgType == 206) {
            //对方是否悔棋
            regret(jsonObject, session);
        } else if (msgType == 207) {
            //重开请求
            reopenMessage(jsonObject, session);
        } else if (msgType == 208) {
            //对方是否重开
            reopen(jsonObject, session);
        }
    }


    /**
     * 向对方发送悔棋请求
     *
     * @param jsonObject
     * @param session
     */
    public void regretMessage(JSONObject jsonObject, Session session) {
        Player otherPlayer = RoomManagerUtils.getRoom(session).getOtherPlayer(session);
        if (otherPlayer.getSession().isOpen()) {
            Map result = new HashMap();
            result.put("msgType", 406);
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
        }
    }

    /**
     * 悔棋确认处理
     *
     * @param jsonObject
     * @param session
     */
    public void regret(JSONObject jsonObject, Session session) {
        int isMe = jsonObject.getIntValue("isMe");
        int isConfirm = jsonObject.getIntValue("isConfirm");

        Room room = RoomManagerUtils.getRoom(session);
        List step;
        //是否改变执棋人 0-改变 1-不改变
        int change;
        if (isConfirm == 0) {
            //确认悔棋
            Player otherPlayer = RoomManagerUtils.getRoom(session).getOtherPlayer(session);
            if (isMe == 0) {
                //对方执棋，只要悔一步
                step = RegretAndReopenUntils.getStep(room, 1);
                change = 0;
            } else {
                //请求方执棋，悔两步
                step = RegretAndReopenUntils.getStep(room, 2);
                change = 1;
            }
            Map result = new HashMap();
            result.put("msgType", 407);
            result.put("isConfirm", 0);
            result.put("change", change);
            result.put("step", step);
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
            SessionUtils.sendMsg(session, result);
        } else {
            //反对悔棋
            Player otherPlayer = RoomManagerUtils.getRoom(session).getOtherPlayer(session);
            Map result = new HashMap();
            result.put("msgType", 407);
            result.put("isConfirm", 1);
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
            SessionUtils.sendMsg(session, result);
        }
    }

    public void reopenMessage(JSONObject jsonObject, Session session) {
        Player otherPlayer = RoomManagerUtils.getRoom(session).getOtherPlayer(session);
        if (otherPlayer.getSession().isOpen()) {
            Map result = new HashMap();
            result.put("msgType", 408);
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
        }
    }

    public void reopen(JSONObject jsonObject, Session session) {
        int isConfirm = jsonObject.getIntValue("isConfirm");

        Room room = RoomManagerUtils.getRoom(session);
        if (isConfirm == 0) {
            //确认重开
            RegretAndReopenUntils.clearStep(room);
            Player otherPlayer = RoomManagerUtils.getRoom(session).getOtherPlayer(session);
            Map result = new HashMap();
            result.put("msgType", 409);
            result.put("isConfirm", 0);
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
            SessionUtils.sendMsg(session, result);
        } else {
            //反对重开
            Player otherPlayer = RoomManagerUtils.getRoom(session).getOtherPlayer(session);
            Map result = new HashMap();
            result.put("msgType", 409);
            result.put("isConfirm", 1);
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
            SessionUtils.sendMsg(session, result);
        }
    }


    /**
     * 语音消息处理
     *
     * @param jsonObject
     * @param session
     */
    public void audioHandler(JSONObject jsonObject, Session session) {
        //获得音频聊天文件
        String audio = jsonObject.getString("audio");

        //获取对手的session
        Room room = RoomManagerUtils.getRoom(session);
        Player otherPlayer = room.getOtherPlayer(session);
        //判断对手是否存在
        if (otherPlayer != null) {
            //将聊天信息 发送给对方
            Map result = new HashMap();
            result.put("msgType", 405);
            result.put("audio", audio);//对方发送的聊天内容
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
        }
    }

    /**
     * 聊天消息处理
     */
    public void infoHandler(JSONObject jsonObject, Session session) {
        //获得聊天的内容
        String info = jsonObject.getString("info");

        //获取对手的session
        Room room = RoomManagerUtils.getRoom(session);
        Player otherPlayer = room.getOtherPlayer(session);
        //判断对手是否存在
        if (otherPlayer != null) {
            //将聊天信息 发送给对方
            Map result = new HashMap();
            result.put("msgType", 404);
            result.put("info", info);//对方发送的聊天内容
            SessionUtils.sendMsg(otherPlayer.getSession(), result);
        }
    }

    /**
     * 处理落子的消息
     */
    public void drawGo(JSONObject jsonObject, Session session) {
        //获得落子的坐标系
        int x = jsonObject.getIntValue("x");
        int y = jsonObject.getIntValue("y");
        int goColor = jsonObject.getIntValue("goColor"); //0 - 黑子 1 - 白子

        //获取正在对局的房间
        Room room = RoomManagerUtils.getRoom(session);

        //获得当前房间的棋盘
        Gobang gobang = room.getGobang();
        //尝试给棋盘落子
        boolean isOk = gobang.go(x, y, goColor);
        if (isOk) {
            //当前落子成功

            RegretAndReopenUntils.setStep(room, new Integer[]{x, y, goColor});
            //判断胜利
            boolean isWin = gobang.isWin(x, y, goColor);

            //如果已经胜利
            if (isWin) {
                //当前的落子的用户 欢乐豆+1000
                Player player = room.getPlayer(session);
                //用户添加1000欢乐豆
                userService.addHappyBean(player.getUser().getId(), 1000);
                //生成一条欢乐豆的历史记录
                HappyBeanHistory happyBeanHistory = new HappyBeanHistory();
                happyBeanHistory.setuId(player.getUser().getId());//玩家用户id
                happyBeanHistory.setType(0);//新增
                happyBeanHistory.setBeanNumber(1000);
                happyBeanHistory.setCreateTime(new Date());
                happyBeanHistory.setSource(1);//对局游戏胜利
                happyBeanHistoryService.insertHistory(happyBeanHistory);

                //对手欢乐豆 -1000
                Player otherPlayer = room.getOtherPlayer(session);
                //用户扣减1000欢乐豆
                userService.addHappyBean(otherPlayer.getUser().getId(), -1000);
                //生成一条欢乐豆的历史记录
                HappyBeanHistory happyBeanHistory2 = new HappyBeanHistory();
                happyBeanHistory2.setuId(otherPlayer.getUser().getId());//玩家用户id
                happyBeanHistory2.setType(1);//扣减
                happyBeanHistory2.setBeanNumber(1000);
                happyBeanHistory2.setCreateTime(new Date());
                happyBeanHistory2.setSource(1);//对局游戏胜利
                happyBeanHistoryService.insertHistory(happyBeanHistory2);
            }

            //通过当前的session获得对手信息
            Player otherPlayer = room.getOtherPlayer(session);
            //获得对手的session信息
            Session otherSession = otherPlayer.getSession();
            //将落子信息告知对手
            Map result = new HashMap();
            result.put("msgType", 402);
            result.put("x", x);
            result.put("y", y);
            result.put("goColor", goColor);
            result.put("isWin", isWin);
            SessionUtils.sendMsg(otherSession, result);

            //将落子的信息再回传给自己
            Map result2 = new HashMap();
            result2.put("msgType", 403);
            result2.put("x", x);
            result2.put("y", y);
            result2.put("goColor", goColor);
            result2.put("isWin", isWin);
            SessionUtils.sendMsg(session, result2);


        }
    }

    /**
     * 创建房间
     */
    public void createRoom(JSONObject jsonObject, Session session) {
        //创建房间的消息
        String info = jsonObject.getString("info");
        String pass = jsonObject.getString("pass");
        //用户信息 - 谁创建的房间
        int uid = jsonObject.getIntValue("uid");
        String nickname = jsonObject.getString("nickname");
        String header = jsonObject.getString("header");

        //封装到User对象
        User user = new User();
        user.setId(uid);
        user.setNickname(nickname);
        user.setHeader(header);

        //将User封装成一个Player对象
        Player player = new Player();
        player.setUser(user);//玩家的用户信息
        player.setSession(session);//玩家的session连接

        //创建一个房间对象
        Room room = new Room();
        room.setRid(number.incrementAndGet());//线程安全
        room.setPlayer1(player);
        room.setStatus(0);//待开始
        room.setInfo(info);//房间信息
        room.setPass(pass);//房间密码

        //房间放入一个管理器中
        RoomManagerUtils.putRoom(room.getRid(), room);
        RoomManagerUtils.putRoom(session, room);
    }

    /**
     * 加入房间
     */
    public void addRoom(JSONObject jsonObject, Session session) {

        //获得加入的房间id
        int rid = jsonObject.getIntValue("rid");
        //获取玩家2 输入的房间密码
        String pass = jsonObject.getString("pass");

        //用户信息 - 谁加入的房间
        int uid = jsonObject.getIntValue("uid");
        String nickname = jsonObject.getString("nickname");
        String header = jsonObject.getString("header");

        //封装到User对象
        User user = new User();
        user.setId(uid);
        user.setNickname(nickname);
        user.setHeader(header);

        //保证添加房间的线程安全
        synchronized ((rid + "").intern()) {
            //获取房间
            Room room = RoomManagerUtils.getRoom(rid);
            //判断房间状态
            if (room == null) {
                //返回给前端 - 房间信息不存在
                Map result = new HashMap<>();
                result.put("msgType", 300);//房间未找到
                SessionUtils.sendMsg(session, result);
                return;
            }

            if (room.getStatus() == 1) {
                //返回给前端 - 有人抢先一步加入房间
                Map result = new HashMap<>();
                result.put("msgType", 301);//房间人数已满
                SessionUtils.sendMsg(session, result);
                return;
            }

            if (!StringUtils.isEmpty(room.getPass()) && !room.getPass().equals(pass)) {
                //房间密码错误
                Map result = new HashMap<>();
                result.put("msgType", 302);//密码错误
                SessionUtils.sendMsg(session, result);
                return;
            }

            //加入房间
            Player player = new Player();
            player.setUser(user);
            player.setSession(session);
            room.setPlayer2(player);//将玩家2设置到房间中
            room.setStatus(1);//修改房价状态 为游戏进行中

            //将玩家2的Session 与 Room关联保存起来
            RoomManagerUtils.putRoom(session, room);

            //交换两个玩家的信息
            //给玩家1发送玩家2的信息
            Map result1 = new HashMap();
            result1.put("msgType", 400);//有人加入房间
            result1.put("uid", room.getPlayer2().getUser().getId());
            result1.put("nickname", room.getPlayer2().getUser().getNickname());
            result1.put("header", room.getPlayer2().getUser().getHeader());
            SessionUtils.sendMsg(room.getPlayer1().getSession(), result1);

            //给玩家2发送玩家1的信息
            Map result2 = new HashMap();
            result2.put("msgType", 401);//加入房间成功
            result2.put("uid", room.getPlayer1().getUser().getId());
            result2.put("nickname", room.getPlayer1().getUser().getNickname());
            result2.put("header", room.getPlayer1().getUser().getHeader());
            SessionUtils.sendMsg(room.getPlayer2().getSession(), result2);
        }
    }
}
